package server

import (
	"context"
	"fmt"
	"gbox-one-machine/conf"
	"gbox-one-machine/log"
	"gbox-one-machine/node"
	"net/http"
	"time"
)

const (
	nodeRoleEventID = "gbox-one-machine-node-role"
)

// IServer interface for server
type IServer interface {
	Run() error
	Stop() error
}

// Run server
func Run(s IServer) {
	if err := s.Run(); err != nil {
		log.Logger.Errorf("Server run err:%s", err)
	}
}

// Stop server
func Stop(s IServer) {
	if err := s.Stop(); err != nil {
		log.Logger.Errorf("Server stop err:%s", err)
	}
}

// NewServer create server
func NewServer(ctx context.Context, cf *conf.Config) (IServer, error) {
	role := node.GetNodeRole()
	switch role {
	case node.RoleSlave:
		return NewSlaveServer(ctx, cf)

	}

	return nil, fmt.Errorf("Error node role: %s", role)

}

// Serve start server
func Serve(ctx context.Context, cf *conf.Config) error {
	chSignel := signel()
	chRestart := make(chan struct{})
	if cf.App.Debug {
		go http.ListenAndServe(fmt.Sprintf(":%v", cf.App.DebugPort), nil)
		log.Logger.Debugf("pprof Masterserver run :%v", cf.App.DebugPort)
	}

SERVER_START:
	//d, err := dao.New(cf.Dao)
	//if err != nil {
	//	return err
	//}
	//
	//role, err := d.GetNodeRole(ctx)
	//if err != nil {
	//	return err
	//}
	//
	//if role == "" {
	//	role = node.RoleMaster
	//}
	//
	//node.SetNodeRole(role)
	//
	srv, err := NewSlaveServer(ctx, cf)
	if err != nil {
		return err
	}

	go Run(srv)
	//
	//// watch node role change
	//go func() {
	//	log.Logger.Infof("Node change watch started")
	//	defer log.Logger.Infof("Node change watch stoped")
	//
	//	for {
	//		select {
	//		case <-chSignel:
	//			return
	//		case <-ctx.Done():
	//			return
	//		default:
	//		}
	//
	//		if err := d.WatchNodeRole(ctx, nodeRoleEventID, func(role string) error {
	//			chRestart <- struct{}{}
	//			Stop(srv)
	//			log.Logger.Infof("Node restart with role: %s", role)
	//			// server will recreate, exit current goroutine
	//			runtime.Goexit()
	//			return nil
	//		}); err != nil {
	//			log.Logger.Errorf("Node role watch err:%s", err)
	//			time.Sleep(time.Second) // reduce cpu load
	//		}
	//	}
	//}()

	select {
	case <-chSignel: // signel event
	case <-chRestart: // restart event
		goto SERVER_START
	}

	Stop(srv)
	timer := time.NewTimer(10 * time.Second)
	go func() {
		select {
		case <-timer.C:
			log.Logger.Fatal("Stop timeout, exit")
		}
	}()

	return nil
}
